/*
 
 TopMind jLynx "jLynx JDBC Framework"
 Copyright (c) 2004-2007. TopMind Systems Inc.
 All rights reserved.
 
 This file is part of TopMind jLynx.
 
 TopMind jLynx is free software; you can redistribute it and/or modify
 it under the terms of the License. See website for License.
 
 */
package net.sf.jlynx;

import java.beans.Introspector;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Bean utils used by jLynx.
 * 
 * $Id: BeanUtils.java 99 2007-06-21 02:51:13Z gritc11 $
 */
public class BeanUtils {

	private static Map cache = new HashMap();

	static String decapitalize(String fieldName) {

		return Introspector.decapitalize(fieldName);

		// return target;
	}

	/**
	 * This method performs in a case-sensitive manner
	 * 
	 */
	public static Map describe(Object target) {

		Map retMap = new HashMap();
		List retList = new LinkedList();
		Method[] methods = (Method[]) cache.get(target.getClass());
		if (methods == null) {
			methods = target.getClass().getMethods();
			cache.put(target.getClass(), methods);
		}

		for (int i = 0; i < methods.length; i++) {

			String method = methods[i].getName();
			if (method.indexOf("set") == 0 || method.indexOf("get") == 0) {
				retList.add(method.substring(3, method.length()));
			} else if (method.indexOf("is") == 0) {// added this in v1.2.1
				retList.add(method.substring(2, method.length()));
			}

		}

		Collections.sort(retList);
		Object[] props = retList.toArray();
		retList.clear();
		for (int i = 0; i < props.length - 1; i++) {

			if (props[i].equals(props[i + 1])) {
				String prop = decapitalize(props[i].toString());
				retMap.put(prop, getValue(prop, target));
			}

		}
		retList = null;
		return retMap;

	}

	public static Class getType(String property, Object target) {

		Class ret = Object.class;
		property = "set" + property;

		Method[] methods = (Method[]) cache.get(target.getClass());
		if (methods == null) {
			methods = target.getClass().getMethods();
			cache.put(target.getClass(), methods);
		}

		for (int i = 0; i < methods.length; i++) {

			if (property.equalsIgnoreCase(methods[i].getName())) {

				Class[] paramClass = methods[i].getParameterTypes();
				if (paramClass.length == 1) {
					return paramClass[0];
				}

			}

		}

		return ret;

	}

	/**
	 * This method performs in a case-insensitive manner
	 * 
	 */
	public static Object getValue(String property, Object target) {

		String get = "get" + property;
		String is = "is" + property;

		Method[] methods = (Method[]) cache.get(target.getClass());
		if (methods == null) {
			methods = target.getClass().getMethods();
			cache.put(target.getClass(), methods);
		}

		for (int i = 0; i < methods.length; i++) {

			if (get.equalsIgnoreCase(methods[i].getName())
					|| is.equalsIgnoreCase(methods[i].getName())) {

				try {
					return methods[i].invoke(target, null);
				} catch (IllegalArgumentException ex) {
					// ex.printStackTrace();
				} catch (IllegalAccessException ex) {
					// ex.printStackTrace();
				} catch (InvocationTargetException ex) {
					// ex.printStackTrace();
				}

			}
		}
		return null;

	}

	/**
	 * This method performs in a case-insensitive manner
	 * 
	 */
	public static void setValue(String property, Object target, Object value) {

		property = "set" + property;

		Method[] methods = (Method[]) cache.get(target.getClass());
		if (methods == null) {
			methods = target.getClass().getMethods();
			cache.put(target.getClass(), methods);
		}

		for (int i = 0; i < methods.length; i++) {

			if (property.equalsIgnoreCase(methods[i].getName())) {

				Class[] paramClass = methods[i].getParameterTypes();
				if (paramClass.length == 1) {

					try {

						methods[i].invoke(target, new Object[] { value });

					} catch (IllegalArgumentException ex) {
						// ex.printStackTrace();
					} catch (IllegalAccessException ex) {
						// ex.printStackTrace();
					} catch (InvocationTargetException ex) {
						// ex.printStackTrace();
					}

				}

			}
		}

	}

	static String toJson(Object bean) {

		if (bean == null)
			return null;

		StringBuffer result = new StringBuffer("{\n\"" + "bean" + "\" : {\n");

		Map pairs = null;
		if (bean instanceof Map)
			pairs = (Map) bean;
		else
			pairs = describe(bean);

		Iterator iter = pairs.keySet().iterator();
		while (iter.hasNext()) {

			Object obj = iter.next();

			result.append("\t\"" + obj + "\" : ");
			Object value = pairs.get(obj);
			if (value instanceof String && value != null)
				result.append("\"" + value + "\"");
			else
				result.append(value);

			if (iter.hasNext())
				result.append(",\n");
			else
				result.append("\n}\n}");

		}

		return result.toString();
	}

	static String toXml(Object bean, String element) {

		StringBuffer sb = new StringBuffer("");

		if (bean == null)
			return null;
		else {

			String className = bean.getClass().getName();
			if (element == null)
				element = className.substring(className.lastIndexOf(".") + 1)
						.toLowerCase();
			sb.append("<" + element + " class=\"" + className + "\">\n");

			if (!(bean instanceof Map)) {
				Map props = BeanUtils.describe(bean);
				Iterator keys = props.keySet().iterator();
				while (keys.hasNext()) {
					String key = keys.next().toString();
					Object value = props.get(key);
					if (value == null)
						value = "";
					sb.append(" <" + key + ">" + value + "</" + key + ">\n");
				}
			} else {
				Iterator keys = ((Map) bean).keySet().iterator();
				while (keys.hasNext()) {
					String key = keys.next().toString();
					Object value = ((Map) bean).get(key);
					if (value == null)
						value = "";
					sb.append(" <" + key + ">" + value + "</" + key + ">\n");
				}
			}

			sb.append("</" + element + ">");

		}
		return sb.toString();
	}

	static String toXml(List list, String element) {
		StringBuffer xml = new StringBuffer();
		Iterator iter = list.iterator();
		while (iter.hasNext()) {
			xml.append(toXml(iter.next(), element) + "\n");
		}
		return xml.toString();
	}

	private BeanUtils() {
	}

}
